﻿using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Fixtures;
using Helpers;
using FluentAssertions;
using System.Data;
using System.Data.SqlClient;
using Moq;

namespace DomainModel.Tests
{
    [TestClass]
    public class AddressTest
    {
        [TestMethod]
        public void Address_IsInValid_IfLine1IsMoreThan100Characters()
        {
            // Arrange
            var address = AddressFixture.GetAddress();
            address.Line1 = "a".Times(101);

            // Act
            address.Errors.Count.Should().Be(1);
            address.IsValid.Should().BeFalse();
            address.Errors[0].Should().Be("Line 1 cannot be more than 100 characters.");
        }

        [TestMethod]
        public void Address_Isvalid_IfLine1Is100Characters()
        {
            // Arrange
            var address = AddressFixture.GetAddress();
            address.Line1 = "a".Times(100);

            // Act
            address.IsValid.Should().BeTrue();
        }

        [TestMethod]
        public void Address_Isvalid_IfLine1IsEmpty()
        {
            // Arrange
            var address = AddressFixture.GetAddress();
            address.Line1 = "";

            // Act
            address.IsValid.Should().BeTrue();
        }

        [TestMethod]
        public void Address_Isvalid_IfLine1IsNull()
        {
            // Arrange
            var address = AddressFixture.GetAddress();
            address.Line1 = null;

            // Act
            address.IsValid.Should().BeTrue();
        }

        [TestMethod]
        public void Address_IsInValid_IfLine2IsMoreThan100Characters()
        {
            // Arrange
            var address = AddressFixture.GetAddress();
            address.Line2 = "a".Times(101);

            // Act
            address.Errors.Count.Should().Be(1);
            address.IsValid.Should().BeFalse();
            address.Errors[0].Should().Be("Line 2 cannot be more than 100 characters.");
        }

        [TestMethod]
        public void Address_Isvalid_IfLine2Is100Characters()
        {
            // Arrange
            var address = AddressFixture.GetAddress();
            address.Line2 = "a".Times(100);

            // Act
            address.IsValid.Should().BeTrue();
        }

        [TestMethod]
        public void Address_Isvalid_IfLine2IsEmpty()
        {
            // Arrange
            var address = AddressFixture.GetAddress();
            address.Line2 = "";

            // Act
            address.IsValid.Should().BeTrue();
        }

        [TestMethod]
        public void Address_Isvalid_IfLine2IsNull()
        {
            // Arrange
            var address = AddressFixture.GetAddress();
            address.Line2 = null;

            // Act
            address.IsValid.Should().BeTrue();
        }

        [TestMethod]
        public void Address_IsInValid_IfCityIsMoreThan30Characters()
        {
            // Arrange
            var address = AddressFixture.GetAddress();
            address.City = "a".Times(31);

            // Act
            address.Errors.Count.Should().Be(1);
            address.IsValid.Should().BeFalse();
            address.Errors[0].Should().Be("City cannot be more than 30 characters.");
        }

        [TestMethod]
        public void Address_Isvalid_IfCityIs30Characters()
        {
            // Arrange
            var address = AddressFixture.GetAddress();
            address.City = "a".Times(30);

            // Act
            address.IsValid.Should().BeTrue();
        }

        [TestMethod]
        public void Address_Isvalid_IfCityIsEmpty()
        {
            // Arrange
            var address = AddressFixture.GetAddress();
            address.City = "";

            // Act
            address.IsValid.Should().BeTrue();
        }

        [TestMethod]
        public void Address_Isvalid_IfCityIsNull()
        {
            // Arrange
            var address = AddressFixture.GetAddress();
            address.City = null;

            // Act
            address.IsValid.Should().BeTrue();
        }

        [TestMethod]
        public void Address_IsInValid_IfStateIsMoreThan30Characters()
        {
            // Arrange
            var address = AddressFixture.GetAddress();
            address.State = "a".Times(31);

            // Act
            address.Errors.Count.Should().Be(1);
            address.IsValid.Should().BeFalse();
            address.Errors[0].Should().Be("State cannot be more than 30 characters.");
        }

        [TestMethod]
        public void Address_Isvalid_IfStateIs30Characters()
        {
            // Arrange
            var address = AddressFixture.GetAddress();
            address.State = "a".Times(30);

            // Act
            address.IsValid.Should().BeTrue();
        }

        [TestMethod]
        public void Address_Isvalid_IfStateIsEmpty()
        {
            // Arrange
            var address = AddressFixture.GetAddress();
            address.State = "";

            // Act
            address.IsValid.Should().BeTrue();
        }

        [TestMethod]
        public void Address_Isvalid_IfStateIsNull()
        {
            // Arrange
            var address = AddressFixture.GetAddress();
            address.State = null;

            // Act
            address.IsValid.Should().BeTrue();
        }

        [TestMethod]
        public void Address_IsInValid_IfPostalCodeIsMoreThan10Characters()
        {
            // Arrange
            var address = AddressFixture.GetAddress();
            address.PostalCode = "a".Times(11);

            // Act
            address.Errors.Count.Should().Be(1);
            address.IsValid.Should().BeFalse();
            address.Errors[0].Should().Be("Postal code cannot be more than 10 characters.");
        }

        [TestMethod]
        public void Address_Isvalid_IfPostalCodeIs10Characters()
        {
            // Arrange
            var address = AddressFixture.GetAddress();
            address.PostalCode = "a".Times(10);

            // Act
            address.IsValid.Should().BeTrue();
        }

        [TestMethod]
        public void Address_Isvalid_IfPostalCodeIsEmpty()
        {
            // Arrange
            var address = AddressFixture.GetAddress();
            address.PostalCode = "";

            // Act
            address.IsValid.Should().BeTrue();
        }

        [TestMethod]
        public void Address_Isvalid_IfPostalCodeIsNull()
        {
            // Arrange
            var address = AddressFixture.GetAddress();
            address.PostalCode = null;

            // Act
            address.IsValid.Should().BeTrue();
        }

        [TestMethod]
        public void AddressProperties_ShouldBeCorrectlyPopulatedFromReader()
        {
            // Arrange            
            var address = AddressFixture.GetAddress();

            var readerMock = new Mock<IDataReader>();
            readerMock.Setup(x => x["HomeAddressLine1"]).Returns(address.Line1);
            readerMock.Setup(x => x["HomeAddressLine2"]).Returns(address.Line2);
            readerMock.Setup(x => x["HomeAddressCity"]).Returns(address.City);
            readerMock.Setup(x => x["HomeAddressState"]).Returns(address.State);
            readerMock.Setup(x => x["HomeAddressPostalCode"]).Returns(address.PostalCode);

            // Act
            var newAddress = new Address(readerMock.Object);

            // Assert
            newAddress.Line1.Should().Be(address.Line1);
            newAddress.Line2.Should().Be(address.Line2);
            newAddress.City.Should().Be(address.City);
            newAddress.State.Should().Be(address.State);
            newAddress.PostalCode.Should().Be(address.PostalCode);
        }

        [TestMethod]
        public void AddressProperties_ShouldBeNull_IfReaderHasDBNull()
        {
            // Arrange            
            var address = AddressFixture.GetAddress();

            var readerMock = new Mock<IDataReader>();
            readerMock.Setup(x => x["HomeAddressLine1"]).Returns(DBNull.Value);
            readerMock.Setup(x => x["HomeAddressLine2"]).Returns(DBNull.Value);
            readerMock.Setup(x => x["HomeAddressCity"]).Returns(DBNull.Value);
            readerMock.Setup(x => x["HomeAddressState"]).Returns(DBNull.Value);
            readerMock.Setup(x => x["HomeAddressPostalCode"]).Returns(DBNull.Value);

            // Act
            var newAddress = new Address(readerMock.Object);

            // Assert
            newAddress.Line1.Should().BeNull();
            newAddress.Line2.Should().BeNull();
            newAddress.City.Should().BeNull();
            newAddress.State.Should().BeNull();
            newAddress.PostalCode.Should().BeNull();
        }
    }
}
